home *** CD-ROM | disk | FTP | other *** search
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include "dbox.h"
- #include "werr.h"
- #include "global.h"
- #include "mbuf.h"
- #include "timer.h"
- #include "icmp.h"
- #include "netuser.h"
- #include "tcp.h"
- #include "telnet.h"
- #include "session.h"
- #include "misc.h"
- #include "domain.h"
-
- static int telnet(int32, char *, char *, char *, struct session *);
- static int telnet_error(char *, char *, struct session *);
- static void free_telnet(struct telnet *);
- static void willopt(struct telnet *, char);
- static void wontopt(struct telnet *, char);
- static void doopt(struct telnet *, char);
- static void dontopt(struct telnet *, char);
- static void answer(struct telnet *, int, int);
-
- #define CTLZ 26
-
- #define TELNET_Connect 0
- #define TELNET_Host 1
- #define TELNET_Port 3
-
- extern char nospace[];
- extern char badhost[];
- int refuse_echo = 0;
- int unix_line_mode = 0; /* if true turn <cr> to <nl> when in line mode */
-
- #ifdef DEBUG
- char *t_options[] = {
- "Transmit Binary",
- "Echo",
- "",
- "Suppress Go Ahead",
- "",
- "Status",
- "Timing Mark"
- };
- #endif
-
- void start_telnet(void)
- {
- struct session *session;
- char buffer[80];
- char Host[256];
- char Port[5];
- dbox d;
-
- if ((d = dbox_new("TELNET")) == NULL)
- return;
-
- dbox_setfield(d, TELNET_Host, "");
- dbox_setfield(d, TELNET_Port, "23");
- dbox_show(d);
-
- if (dbox_fillin(d) == TELNET_Connect)
- {
- dbox_getfield(d, TELNET_Host, Host, 255);
- dbox_getfield(d, TELNET_Port, Port, 4);
-
- /* Allocate a session descriptor */
- sprintf(buffer, "TELNET - %.60s", Host);
- if ((session = newsession(buffer)) == NULLSESSION)
- {
- werr(0, "Too many sessions");
- return;
- }
-
- session->name = strdup(Host);
- session->type = RESOLVING;
- session->parse = NULLVFP;
-
- sprintf(buffer, "Resolving %.60s ...\n", Host);
- Window_Write(session->window, buffer, strlen(buffer));
-
- resolve_a(Host, Port, NULLCHAR, session, telnet, telnet_error);
- }
-
- dbox_dispose(&d);
- }
-
- static int telnet_error(char *host, char *message, struct session *s)
- {
- char buffer[80];
-
- sprintf(buffer, "Cannot TELNET to %s - %s\n", host, message);
- Window_Write(s->window, buffer, strlen(buffer));
-
- detachsession(s);
-
- return 0;
- }
-
- /* Execute user telnet command */
- static int telnet(int32 address, char *host, char *port, char *arg2, struct session *s)
- {
- char buffer[80];
- struct telnet *tn;
- struct tcb *tcb;
- struct socket lsocket, fsocket;
-
- host = host;
- arg2 = arg2;
-
- lsocket.address = ip_addr;
- lsocket.port = lport++;
-
- fsocket.address = address;
- fsocket.port = (atoi(port) > 0) ? atoi(port) : TELNET_PORT;
-
- s->type = TELNET;
- s->addr = fsocket.address;
-
- if ((refuse_echo == 0) && (unix_line_mode != 0))
- s->parse = unix_send_tel;
- else
- s->parse = send_tel;
-
- s->echo = 0;
- s->raw = 1;
-
- /* Create and initialize a Telnet protocol descriptor */
- if((tn = (struct telnet *)calloc(1,sizeof(struct telnet))) == NULLTN)
- {
- Window_Write(s->window, nospace, strlen(nospace));
- detachsession(s);
- return 1;
- }
-
- tn->session = s; /* Upward pointer */
- tn->state = TS_DATA;
- s->cb.telnet = tn; /* Downward pointer */
-
- sprintf(buffer, "Trying [%s] ...\n", inet_ntoa(address));
- Window_Write(s->window, buffer, strlen(buffer));
-
- tcb = open_tcp(&lsocket,&fsocket,TCP_ACTIVE,0,
- (void (*)())rcv_char,(void(*)())tn_tx,(void(*)())t_state,0,(char *)tn);
-
- tn->tcb = tcb; /* Downward pointer */
-
- return 0;
- }
-
- /* Process typed characters */
- void unix_send_tel(struct session *session, char *buf, int16 n)
- {
- int i;
-
- for (i=0; (i<n) && (buf[i] != '\r'); i++)
- ;
- if (buf[i] == '\r') {
- buf[i] = '\n';
- n = i+1;
- }
- send_tel(session, buf,n);
- }
-
- void send_tel(struct session *session, char *buf, int16 n)
- {
- struct mbuf *bp;
-
- if(session->cb.telnet == NULLTN || session->cb.telnet->tcb == NULLTCB)
- return;
- bp = qdata(buf,n);
- send_tcp(session->cb.telnet->tcb, bp);
- }
-
- /* Process incoming TELNET characters */
- void tel_input(register struct telnet *tn, struct mbuf *bp)
- {
- char c;
- register char *s;
- char *line;
-
- if ((line = s = malloc(len_mbuf(bp) + 1)) == NULL)
- {
- free_p(bp);
- return;
- }
-
- /* Optimization for very common special case -- no special chars */
- if(tn->state == TS_DATA){
- while(bp != NULLBUF && memchr(bp->data,IAC,bp->cnt) == NULLCHAR){
- while (bp->cnt-- != 0) *s++ = *bp->data++;
- bp = free_mbuf(bp);
- }
- }
-
- while (pullup(&bp,&c,1) == 1) {
- switch(tn->state){
- case TS_DATA:
- if(uchar(c) == IAC){
- tn->state = TS_IAC;
- } else {
- if(!tn->remote[TN_TRANSMIT_BINARY])
- *s++ = c & 0x7f;
- }
- break;
- case TS_IAC:
- switch(uchar(c)){
- case WILL:
- tn->state = TS_WILL;
- break;
- case WONT:
- tn->state = TS_WONT;
- break;
- case DO:
- tn->state = TS_DO;
- break;
- case DONT:
- tn->state = TS_DONT;
- break;
- case IAC:
- Window_Write(tn->session->window, &c, 1);
- tn->state = TS_DATA;
- break;
- default:
- tn->state = TS_DATA;
- break;
- }
- break;
- case TS_WILL:
- willopt(tn,c);
- tn->state = TS_DATA;
- break;
- case TS_WONT:
- wontopt(tn,c);
- tn->state = TS_DATA;
- break;
- case TS_DO:
- doopt(tn,c);
- tn->state = TS_DATA;
- break;
- case TS_DONT:
- dontopt(tn,c);
- tn->state = TS_DATA;
- break;
- }
- }
- Window_Write(tn->session->window, line, s - line);
- free(line);
- }
-
- /* Telnet receiver upcall routine */
- void rcv_char(register struct tcb *tcb, int16 cnt)
- {
- struct mbuf *bp;
- struct telnet *tn;
-
- if((tn = (struct telnet *)tcb->user) == NULLTN){
- /* Unknown connection; ignore it */
- return;
- }
-
- if(recv_tcp(tcb,&bp,cnt) > 0)
- tel_input(tn,bp);
- }
-
- /* Handle transmit upcalls. Used only for file uploading */
- void tn_tx(struct tcb *tcb, int16 cnt)
- {
- tcb = tcb;
- cnt = cnt;
- }
-
- /* State change upcall routine */
- void t_state(register struct tcb *tcb, char old, char new)
- {
- char buffer[40];
- struct telnet *tn;
- extern char *tcpstates[];
- extern char *reasons[];
- extern char *unreach[];
- extern char *exceed[];
-
- old = old;
-
- /* Can't add a check for unknown connection here, it would loop
- * on a close upcall! We're just careful later on.
- */
- tn = (struct telnet *)tcb->user;
-
- switch(new){
- case CLOSE_WAIT:
- sprintf(buffer,"%s\n",tcpstates[new]);
- Window_Write(tn->session->window,buffer,strlen(buffer));
- close_tcp(tcb);
- break;
- case CLOSED: /* court adjourned */
- sprintf(buffer,"%s (%s",tcpstates[new],reasons[tcb->reason]);
- Window_Write(tn->session->window,buffer,strlen(buffer));
- if(tcb->reason == NETWORK){
- switch(tcb->type){
- case DEST_UNREACH:
- sprintf(buffer,": %s unreachable",unreach[tcb->code]);
- Window_Write(tn->session->window,buffer,strlen(buffer));
- break;
- case TIME_EXCEED:
- sprintf(buffer,": %s time exceeded",exceed[tcb->code]);
- Window_Write(tn->session->window,buffer,strlen(buffer));
- break;
- }
- }
- Window_Write(tn->session->window,")\n",2);
- del_tcp(tcb);
- if(tn != NULLTN)
- free_telnet(tn);
- break;
- default:
- sprintf(buffer,"%s\n",tcpstates[new]);
- Window_Write(tn->session->window,buffer,strlen(buffer));
- break;
- }
- }
-
- /* Delete telnet structure */
- static void free_telnet(struct telnet *tn)
- {
- if(tn->session != NULLSESSION)
- detachsession(tn->session);
-
- if(tn != NULLTN)
- free((char *)tn);
- }
-
- /* The guts of the actual Telnet protocol: negotiating options */
- static void willopt(struct telnet *tn, char opt)
- {
- int ack;
-
- #ifdef DEBUG
- char buffer[80];
-
- if(uchar(opt) <= NOPTIONS)
- sprintf(buffer,"recv: will %s\n",t_options[opt]);
- else
- sprintf(buffer,"recv: will %u\n",opt);
- Window_Write(tn->session->window,buffer,strlen(buffer));
- #endif
-
- switch(uchar(opt)){
- case TN_TRANSMIT_BINARY:
- case TN_ECHO:
- case TN_SUPPRESS_GA:
- if(tn->remote[uchar(opt)] == 1)
- return; /* Already set, ignore to prevent loop */
- if(uchar(opt) == TN_ECHO){
- if(refuse_echo){
- /* User doesn't want to accept */
- ack = DONT;
- break;
- } else
- tn->session->raw = 1; /* Put tty into raw mode */
- }
- tn->remote[uchar(opt)] = 1;
- ack = DO;
- break;
- default:
- ack = DONT; /* We don't know what he's offering; refuse */
- }
- answer(tn,ack,opt);
- }
- static void wontopt(struct telnet *tn, char opt)
- {
- #ifdef DEBUG
- char buffer[80];
-
- if(uchar(opt) <= NOPTIONS)
- sprintf(buffer,"recv: wont %s\n",t_options[uchar(opt)]);
- else
- sprintf(buffer,"recv: wont %u\n",uchar(opt));
- Window_Write(tn->session->window,buffer,strlen(buffer));
- #endif
- if(uchar(opt) <= NOPTIONS){
- if(tn->remote[uchar(opt)] == 0)
- return; /* Already clear, ignore to prevent loop */
- tn->remote[uchar(opt)] = 0;
- if(uchar(opt) == TN_ECHO)
- tn->session->raw = 0; /* Put tty into cooked mode */
- }
- answer(tn,DONT,opt); /* Must always accept */
- }
- static void doopt(struct telnet *tn, char opt)
- {
- int ack;
-
- #ifdef DEBUG
- char buffer[80];
-
- if(uchar(opt) <= NOPTIONS)
- sprintf(buffer,"recv: do %s\n",t_options[uchar(opt)]);
- else
- sprintf(buffer,"recv: do %u\n",uchar(opt));
- Window_Write(tn->session->window,buffer,strlen(buffer));
- #endif
- switch(uchar(opt)){
- #ifdef FUTURE /* Use when local options are implemented */
- if(tn->local[uchar(opt)] == 1)
- return; /* Already set, ignore to prevent loop */
- tn->local[uchar(opt)] = 1;
- ack = WILL;
- break;
- #endif
- default:
- ack = WONT; /* Don't know what it is */
- }
- answer(tn,ack,opt);
- }
- static void dontopt(struct telnet *tn, char opt)
- {
- #ifdef DEBUG
- char buffer[80];
-
- if(uchar(opt) <= NOPTIONS)
- sprintf(buffer,"recv: dont %s\n",t_options[uchar(opt)]);
- else
- sprintf(buffer,"recv: dont %u\n",uchar(opt));
- Window_Write(tn->session->window,buffer,strlen(buffer));
- #endif
- if(uchar(opt) <= NOPTIONS){
- if(tn->local[uchar(opt)] == 0){
- /* Already clear, ignore to prevent loop */
- return;
- }
- tn->local[uchar(opt)] = 0;
- }
- answer(tn,WONT,opt);
- }
- static void answer(struct telnet *tn, int r1, int r2)
- {
- struct mbuf *bp;
- char s[3];
-
- #ifdef DEBUG
- switch(r1){
- case WILL:
- cwprintf("sent: will ");
- break;
- case WONT:
- cwprintf("sent: wont ");
- break;
- case DO:
- cwprintf("sent: do ");
- break;
- case DONT:
- cwprintf("sent: dont ");
- break;
- }
- if(r2 <= 6)
- cwprintf("%s\n",t_options[r2]);
- else
- cwprintf("%u\n",r2);
- #endif
-
- s[0] = IAC;
- s[1] = r1;
- s[2] = r2;
- bp = qdata(s,(int16)3);
- send_tcp(tn->tcb,bp);
- }
-